﻿import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

public class RSAEncryptDecrypt {
	
	//================================================================================
    // Properties
    //================================================================================

	private Cipher cipherRSA;
    private KeyPairGenerator keyGen;
    private byte[] decrypted = null;
    private byte[] encrypted = null;
    private FileOutputStream fospb = null;
    private FileOutputStream fospv = null;
    private FileInputStream fispb = null;
    private FileInputStream fispv = null;
    private X509EncodedKeySpec keySpec = null;
    private PKCS8EncodedKeySpec keySpecpv = null;
    private KeyFactory keyFactory = null;
    
    static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    static SecureRandom rnd = new SecureRandom();
    
    //================================================================================
    // Constructors
    //================================================================================
    
    public RSAEncryptDecrypt() {
        try {
        	keyGen = KeyPairGenerator.getInstance("RSA");
        	keyGen.initialize(2048, rnd);
        	
            cipherRSA = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            
            
        } catch (Exception ex) {
        	ex.printStackTrace();
        } 
    }
    
    //================================================================================
    // Method
    //================================================================================
    
    // สร้าง Public Key และ Private Key
    public void generateKeyRSA(String SecurepubName, String SecureprvName) throws Exception {
		
        KeyPair keyPair = null;
        
        try {
            keyGen = KeyPairGenerator.getInstance("RSA");
			SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
			keyGen.initialize(2048, random);
			keyPair = keyGen.generateKeyPair();
			RSAPrivateKey privKey = (RSAPrivateKey) keyPair.getPrivate();
			//RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic();

			/* Save the private key in a file */
			PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privKey.getEncoded());
			FileOutputStream keyfos = new FileOutputStream(SecureprvName);
			keyfos.write(pkcs8EncodedKeySpec.getEncoded());
			System.out.println("***private key : " + pkcs8EncodedKeySpec);
			keyfos.close();

			/* Save the public key in a file */
			//X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey.getEncoded());
			X509CertificateGenerator generator = new X509CertificateGenerator();
			X509Certificate cert = generator.generateCertificate("CN=SE2", keyPair, 360,"SHA256WithRSA");
			
			FileOutputStream keyfos1 = new FileOutputStream(SecurepubName);
			keyfos1.write("-----BEGIN CERTIFICATE-----\n".getBytes("US-ASCII"));
			keyfos1.write(Base64.encodeBase64(cert.getEncoded(), true));
			keyfos1.write("-----END CERTIFICATE-----\n".getBytes("US-ASCII"));			
			//System.out.println("***public key : " + x509EncodedKeySpec);
			keyfos1.close();

        } catch (Exception ex) {
        	ex.printStackTrace();
        } finally {
        }
    }
    
    // อ่าน Public Key
    public RSAPublicKey LoadPublicKeyRSA(String SecurepubName) throws Exception {
    	FileInputStream fr = new FileInputStream(SecurepubName);
		CertificateFactory cf = CertificateFactory.getInstance("X509");
		X509Certificate cert = (X509Certificate)cf.generateCertificate(fr);
		return (RSAPublicKey)cert.getPublicKey();
    }
    
    // อ่าน Private Key
    public RSAPrivateKey LoadPrivateKeyRSA(String SecureprvName) throws Exception {
    	PrivateKey privateKeyRSA = null;
    	
    	try {
    		fispv = new FileInputStream(SecureprvName);
			byte[] keyBytesprivate = new byte[fispv.available()];
			fispv.read(keyBytesprivate);
    	   
    	    keyFactory = KeyFactory.getInstance("RSA");
    	    
    	    keySpecpv = new PKCS8EncodedKeySpec(keyBytesprivate);
    	    privateKeyRSA = keyFactory.generatePrivate(keySpecpv);
    	    
    	    return (RSAPrivateKey)privateKeyRSA;
    	    
    	}
    	catch(Exception ex){
    		ex.printStackTrace();
    		return (RSAPrivateKey)privateKeyRSA;
    	}
    	finally
    	{
    	    fispv.close();
    	}
    }
    
    // แปลง PublicKey เป็น RSAPublicKeySpec
    public RSAPublicKeySpec LoadRSAPublicKeySpec(PublicKey publicKey) throws Exception {
    	RSAPublicKeySpec pubSpec = null;
		KeyFactory fact = KeyFactory.getInstance("RSA");
		
    	try {
    		pubSpec = fact.getKeySpec(publicKey,RSAPublicKeySpec.class);
    	    
    	    return pubSpec;
    	}
    	catch(Exception ex){
    		ex.printStackTrace();
    		return pubSpec;
    	}
    }
    
    // แปลง PrivateKey เป็น RSAPrivateKeySpec
    public RSAPrivateKeySpec LoadRSAPrivateKeySpec(PrivateKey privateKey) throws Exception {
    	RSAPrivateKeySpec pubSpec = null;
		KeyFactory fact = KeyFactory.getInstance("RSA");
		
    	try {
    		pubSpec = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);
    	    
    	    return pubSpec;
    	}
    	catch(Exception ex){
    		ex.printStackTrace();
    		return pubSpec;
    	}
    }
    
    // ถอดรหัส RSA
    public byte[] decryptRSA(byte[] Message, PrivateKey privateKey) throws Exception {
    	cipherRSA.init(Cipher.DECRYPT_MODE, privateKey);
    	decrypted = cipherRSA.doFinal(Message);
    	
    	return decrypted;
    }
    
    // เข้า รหัส RSA
    public byte[] encryptRSA(byte[] Message, PublicKey publicKey) throws Exception {
    	cipherRSA.init(Cipher.ENCRYPT_MODE, publicKey);
        encrypted = cipherRSA.doFinal(Message);
        
        return encrypted;
    }
}
